package com.since.data_structure.tree;

import java.io.*;
import java.util.Map;
import java.util.Objects;

/**
 * Created by Sincerity on 2020/5/23.
 * 描述：对文件的哈夫曼压缩 通常文件下都是有效的,但是比如对视频
 * ppt等已经压缩过的文件效果不是很明显
 * 这是一种基于文件的无损压缩
 * 1. 文件的压缩 (如果文件已经是压缩文件效果不是很明显) {@link #FileZip(String, String)}
 * 2. 文件的解压 {@link #unzipFiles(String, String)}
 */
class FileHuffmanZip {
    public static void main(String[] args) {
        FileHuffmanZip huffmanZip = new FileHuffmanZip();
        //测试压缩文件
        String srcFile = "c://1.md";
        String dstFile = "c://1.zip";
        String srcFile2 = "c://111.md";
//        boolean b = huffmanZip.FileZip(srcFile, dstFile);
//        System.out.println("压缩文件" + b);
        //测试解压
        boolean b = huffmanZip.unzipFiles(dstFile, srcFile2);
        System.out.println("解压文件" + b);
    }

    /**
     * 解压文件
     *
     * @param fileSaveDir 压缩文件的存储位置
     * @param fileDir     解压后文件的输出位置
     * @return 解压是否成功
     */
    private boolean unzipFiles(String fileSaveDir, String fileDir) {
        FileInputStream inputStream = null;
        FileOutputStream outputStream = null;
        ObjectInputStream objectInputStream = null;
        try {
            inputStream = new FileInputStream(fileSaveDir);
            objectInputStream = new ObjectInputStream(inputStream);
            byte[] b = (byte[]) objectInputStream.readObject();
            Map<Byte, String> huffmanCodes = (Map<Byte, String>) objectInputStream.readObject();
            //开始解码
            byte[] decode = HuffmanCode.decode(b, huffmanCodes);
            outputStream = new FileOutputStream(fileDir);
            outputStream.write(decode);

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                Objects.requireNonNull(outputStream).close();
                Objects.requireNonNull(objectInputStream).close();
                Objects.requireNonNull(inputStream).close();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
        return true;
    }

    /**
     * 压缩文件
     *
     * @param fileDir     文件存放位置
     * @param fileSaveDir 压缩后文件存放位置
     * @return 是否压缩成功
     */
    private boolean FileZip(String fileDir, String fileSaveDir) {
        FileInputStream is = null;
        FileOutputStream os = null;
        ObjectOutputStream oos = null;
        try {
            is = new FileInputStream(fileDir);
            byte[] b = new byte[is.available()];
            int read = is.read(b);
            byte[] huffmanBytes = null;
            if (read != -1) {
                huffmanBytes = HuffmanCode.huffmanZip(b);
                os = new FileOutputStream(fileSaveDir);
            }
            oos = new ObjectOutputStream(os);
            //不仅仅要存哈夫曼编码后的byte数组 ,还要存哈夫曼的编码表
            oos.writeObject(huffmanBytes);
            oos.writeObject(HuffmanCode.getHuffmanCodes(b));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                Objects.requireNonNull(oos).close();
                Objects.requireNonNull(os).close();
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }
}
